#include "datastream.h"

DataStream::DataStream(const string& filename, iomode mode):
mFileName(filename),
mMode(mode)
{
    // NOOP
}

DataStream::~DataStream()
{
    // NOOP
}

DataStream* DataStream::create(ClassId* classId, const string& name, iomode mode)
{
    assert(classId);

    string filename = classId->getPathName() + name + classId->getExtension();
    if ((mode == Input) && (!boost::filesystem::exists(filename)))
        return 0;
    return new FileStream(filename, mode);
}

void DataStream::destroy(DataStream* ds)
{
    assert(ds);
    delete ds;
}

// string read/write operators
template <>
bool DataStream::operator >> (string& s)
{
    Uint32 size;

    *this >> size;
    s.resize(size);
    return read(&s[0], size);
}

template <>
bool DataStream::operator << (const string& s)
{
    Uint32 size = s.size();

    *this << size;
    return write(&s[0], size);
}

// Instance* read/write operators
template <>
bool DataStream::operator >> (Instance*& instance)
{
    ClassId* classId = 0;
    DataStream* ds = 0;
    Uint32 hash = 0;
    string name;

    try {
        if(! (*this >> hash))
            throw ("Could not read ClassId hash");
        if(!hash) {
            instance = 0;
            return true;
        }
        if(! (classId = ClassId::getFromHash(hash)))
            throw ("Could not get ClassId from hash");
        if(! (*this >> name))
            throw ("Could not read Instance name");
        if(! (ds = DataStream::create(classId, name, Input)))
            throw ("Could not create DataStream from ClassId and name");
        if(! (instance = classId->allocate(name, classId)))
            throw ("Could not allocate Instance");
        if(!instance->load(ds))
            throw ("Could not load Instance");
    }
    catch (const char *error) {
        cerr << "DataStream::operator >> (instance) : " << error << endl;
        if(ds)
            DataStream::destroy(ds);
        return false;
    }
    DataStream::destroy(ds);
    return true;
}

template <>
bool DataStream::operator << (Instance* const & instance)
{
    DataStream* ds = 0;
    Uint32 hash = 0;
    string name;

    try {
        if(!instance) {
            if(! (*this << hash))
                throw ("Could not write ClassId hash (0)");
            return true;
        }
        hash = instance->getClassId()->getHash();
        if(! (*this << hash))
            throw ("Could not write ClassId hash");
        name = instance->getName();
        if(! (*this << name))
            throw ("Could not write Instance name");
        if(! (ds = DataStream::create(instance->getClassId(), instance->getName(), Output)))
            throw ("Could not create DataStream from ClassId and name");
        if(!instance->save(ds))
            throw ("Could not save Instance");
    }
    catch (const char* error) {
        cerr << "DataStream::operator << (instance) : " << error << endl;
        if(ds)
            DataStream::destroy(ds);
        return false;
    }
    DataStream::destroy(ds);
    return true;
}
